package net.qiqbframework.config;


import net.qiqbframework.commandhandling.CommandBus;
import net.qiqbframework.common.Registration;
import net.qiqbframework.common.transaction.TransactionManager;
import net.qiqbframework.eventhandling.EventBus;
import net.qiqbframework.lifecycle.LifecycleHandlerRegister;
import net.qiqbframework.messaging.Message;
import net.qiqbframework.messaging.annotation.ExecutableHandlerWrapper;
import net.qiqbframework.messaging.annotation.MessageHandlingMemberFactory;
import net.qiqbframework.messaging.correlation.CorrelationDataProvider;
import net.qiqbframework.messaging.monitoring.MessageMonitor;
import net.qiqbframework.serialization.Serializer;
import net.qiqbframework.tracing.SpanFactory;

import javax.annotation.Nonnull;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * Configuration 接口
 */
public interface Configurer extends LifecycleHandlerRegister {


    Configurer configureMessageMonitor(@Nonnull Function<Configuration, BiFunction<Class<?>, String, MessageMonitor<Message<?>>>> messageMonitorFactoryBuilder);


    default Configurer configureMessageMonitor(@Nonnull Class<?> componentType, @Nonnull Function<Configuration, MessageMonitor<Message<?>>> messageMonitorBuilder) {
        return configureMessageMonitor(componentType, (configuration, type, name) -> messageMonitorBuilder.apply(configuration));
    }

    Configurer configureMessageMonitor(@Nonnull Class<?> componentType, @Nonnull MessageMonitorFactory messageMonitorFactory);


    default Configurer configureMessageMonitor(@Nonnull Class<?> componentType, @Nonnull String componentName, @Nonnull Function<Configuration, MessageMonitor<Message<?>>> messageMonitorBuilder) {
        return configureMessageMonitor(componentType, componentName, (configuration, type, name) -> messageMonitorBuilder.apply(configuration));
    }


    Configurer configureMessageMonitor(@Nonnull Class<?> componentType, @Nonnull String componentName, @Nonnull MessageMonitorFactory messageMonitorFactory);

    Configurer configureCorrelationDataProviders(@Nonnull Function<Configuration, List<CorrelationDataProvider>> correlationDataProviderBuilder);


    Configurer registerModule(@Nonnull ModuleConfiguration module);


    <C> Configurer registerComponent(@Nonnull Class<C> componentType, @Nonnull Function<Configuration, ? extends C> componentBuilder);


    Configurer registerCommandHandler(@Nonnull Function<Configuration, Object> commandHandlerBuilder);


    Configurer registerLoadHandler(@Nonnull Function<Configuration, Object> loadHandlerBuilder);


    Configurer registerLoadHandler(@Nonnull Function<Configuration, Object> loadHandlerBuilder, BiFunction<Configuration, Object, Registration> messageHandlerSubscriber);

    Configurer registerPersistHandler(@Nonnull Function<Configuration, Object> loadHandlerBuilder);


    Configurer registerMessageHandler(@Nonnull Function<Configuration, Object> messageHandlerBuilder);

    default Configurer configureEventBus(@Nonnull Function<Configuration, EventBus> eventBusBuilder) {
        return registerComponent(EventBus.class, eventBusBuilder);
    }

    default Configurer configureCommandBus(@Nonnull Function<Configuration, CommandBus> commandBusBuilder) {
        return registerComponent(CommandBus.class, commandBusBuilder);
    }


    default Configurer configureSerializer(@Nonnull Function<Configuration, Serializer> serializerBuilder) {
        return registerComponent(Serializer.class, serializerBuilder);
    }

    Configurer configureEventSerializer(@Nonnull Function<Configuration, Serializer> eventSerializerBuilder);


    Configurer configureMessageSerializer(@Nonnull Function<Configuration, Serializer> messageSerializerBuilder);


    default Configurer configureTransactionManager(@Nonnull Function<Configuration, TransactionManager> transactionManagerBuilder) {
        return registerComponent(TransactionManager.class, transactionManagerBuilder);
    }

    default Configurer configureTags(@Nonnull Function<Configuration, TagsConfiguration> tagsBuilder) {
        return registerComponent(TagsConfiguration.class, tagsBuilder);
    }

    <A> Configurer registerConfigureAggregate(@Nonnull AggregateConfiguration<A> aggregateConfiguration);



    Configurer registerHandlerDefinition(@Nonnull BiFunction<Configuration, Class, MessageHandlingMemberFactory> handlerDefinitionClass);

    Configurer registerHandlerEnhancerDefinition(Function<Configuration, ExecutableHandlerWrapper> handlerEnhancerBuilder);

    default Configurer configureSpanFactory(@Nonnull Function<Configuration, SpanFactory> spanFactory) {
        return registerComponent(SpanFactory.class, spanFactory);
    }

    EventProcessingConfigurer eventProcessing() throws ConfigurationException;


    default Configurer eventProcessing(@Nonnull Consumer<EventProcessingConfigurer> eventProcessingConfigurer) throws ConfigurationException {
        eventProcessingConfigurer.accept(eventProcessing());
        return this;
    }

    default Configurer registerEventHandler(@Nonnull Function<Configuration, Object> eventHandlerBuilder) {
        eventProcessing().registerEventHandler(eventHandlerBuilder);
        return this;
    }

    default Configurer configureLifecyclePhaseTimeout(long timeout, TimeUnit timeUnit) {
        return this;
    }

    default void onInitialize(@Nonnull Consumer<Configuration> initHandler) {
        registerModule(new ModuleConfiguration() {
            @Override
            public void initialize(Configuration config) {
                initHandler.accept(config);
            }
        });
    }


    Configuration buildConfiguration();


    default Configuration start() {
        Configuration configuration = buildConfiguration();
        configuration.start();
        return configuration;
    }
}
